
#if defined(VIEW_ARRAY_ID) || (defined(MultiviewSinglePass) && (MultiviewSinglePass > 1))
  #ifndef VIEW_ARRAY_ID
    #define VIEW_ARRAY_ID int(vGetViewID())
  #endif
#endif

void updateFinalColor(inout vec4 finalColor, inout vec4 weightedColorSum, uint nbOfFragmentsWithSameDepth)
{
  if (nbOfFragmentsWithSameDepth > 1)
  { // then we turn weightedColorSum into a final aggregated weighted color
    if (weightedColorSum.a > 0.f)
      weightedColorSum.rgb /= weightedColorSum.a; // weighted average (at that point, weightedColorSum.a is the sum of alphas)
    weightedColorSum.a /= float(nbOfFragmentsWithSameDepth); // average alpha
    weightedColorSum.a = 1 - max(vPow(1.0 - weightedColorSum.a, nbOfFragmentsWithSameDepth), 0); // heuristic for final aggregated alpha (ensures that it gives the correct result if all alphas are the same, in particular)
    weightedColorSum.rgb *= weightedColorSum.a; // we alpha-weight the weighted average color with the value of the final aggregated alpha
  }
  // now weightedColorSum is actually an alpha-weighted color (which possibly aggregates several fragments with same depths)
  finalColor.rgb = weightedColorSum.rgb + (1.0 - weightedColorSum.a) * finalColor.rgb;
  finalColor.a = weightedColorSum.a + (1.0 - weightedColorSum.a) * finalColor.a;
}

void main()
{
#ifdef VIEW_ARRAY_ID
  ivec3 fragCoord = ivec3(gl_FragCoord.xy, VIEW_ARRAY_ID);
#else
  ivec2 fragCoord = ivec2(gl_FragCoord.xy);
#endif

#ifndef IS_MSAA
  vec4 finalColor = texelFetch(s_BackBuffer, fragCoord, 0);
#else
  vec4 finalColor = texelFetch(s_BackBuffer, fragCoord, gl_SampleID);
#endif

#ifdef OIT_TAIL_WA

#ifdef VIEW_ARRAY_ID
  vec3 texCoord = vec3(vTexCoord.xy, float(VIEW_ARRAY_ID));
#else
  vec2 texCoord = vec2(vTexCoord.xy);
#endif

 vec4 sumColor = vTexture(s_Tail, texCoord);
 float n = vTexture(s_TailDepth, texCoord).r;

  if(n > 0.01 && sumColor.a > 0.01)
  {
    vec3  avgColor = max(sumColor.rgb, vec3(0.0)) / sumColor.a;
    float avgAlpha = sumColor.a   / n;

    float tmp = max(vPow(1.0 - avgAlpha, n),0);

    vec4 src = vec4(avgColor, 1.0-tmp);
    finalColor.rgb = src.a * src.rgb + (1.0-src.a) * finalColor.rgb;
    finalColor.a = src.a + (1-src.a)*finalColor.a;
  //  finalColor = sumColor / n;
  }

#endif

  const int nbLayerOIT = OIT_MAX_LIST;
#ifdef VIEW_ARRAY_ID
  const int viewOffset = nbLayerOIT * VIEW_ARRAY_ID;
#else
  const int viewOffset = 0;
#endif

#ifdef OIT_DEBUG_LAYER

  float layerId = float(viewOffset) + OIT_DEBUG_LAYER - 1;
  if(int(OIT_DEBUG_LAYER-1) < OIT_MAX_LIST)
  {
    vec3 texCoord = vec3(vTexCoord.xy, layerId);
    uvec4 texelValue = vTexture(s_SourceTex, texCoord);
    finalColor = _GetColor(texelValue);
  }
  else
  {
  }

#else

  {
    int i = viewOffset + nbLayerOIT - 1;
    vec3 texCoord = vec3(vTexCoord.xy, i);

    float lastDepth = uintBitsToFloat(depthUntag(vTexture(s_DepthsTex, texCoord).x));
    vec4 weightedColorSum = _GetColor(vTexture(s_SourceTex, texCoord));
    weightedColorSum.rgb *= weightedColorSum.a;
    uint nbOfFragmentsWithSameDepth = 1;

    for (i = viewOffset + nbLayerOIT - 2; i >= viewOffset; i--)
    {
      texCoord = vec3(vTexCoord.xy, i);
      float depth = uintBitsToFloat(depthUntag(vTexture(s_DepthsTex, texCoord).x));
      vec4 weightedColor = _GetColor(vTexture(s_SourceTex, texCoord));
      weightedColor.rgb *= weightedColor.a;
      if (abs(depth - lastDepth) <= g_depthFightThreshold)
      { // fragments have same depth or are depth fighting; we cannot say which is in front of which so we fall back to a commutative weighted average
        nbOfFragmentsWithSameDepth++;
        weightedColorSum += weightedColor;
        lastDepth = depth;
      }
      else
      {
        updateFinalColor(finalColor, weightedColorSum, nbOfFragmentsWithSameDepth);
        nbOfFragmentsWithSameDepth = 1;
        weightedColorSum = weightedColor;
        lastDepth = depth;
      }
    }
    updateFinalColor(finalColor, weightedColorSum, nbOfFragmentsWithSameDepth);
  }

#endif

  FRAGCOLOR = finalColor;
}
